import json
import logging
import os
import io
import re
from typing import Any
import PyPDF2
import aiofiles.os
from fastapi import UploadFile

from price_analysis.core.config import settings

logger = logging.getLogger("main")


class JsonFileSupport:
    def __init__(self, file_path):
        self.file_path = file_path
        self.logger = logger.getChild("FileSupport")

    def check_dir_exists(self):
        path_dir = os.path.dirname(self.file_path)
        if not os.path.isdir(path_dir):
            os.makedirs(path_dir, exist_ok=True)

    def check_file_exists(self) -> bool:
        if os.path.isfile(self.file_path):
            self.logger.info(f"файл {self.file_path} существует")
            return True
        self.logger.warning(f"файл {self.file_path} не существует")
        return False

    async def read_json_file(self):
        self.logger.info(f"Чтение файла {self.file_path}")

        if not self.check_file_exists():
            self.logger.error(f"файл {self.file_path} не найден")
            return {"error": "file not found"}

        async with aiofiles.open(self.file_path, mode="r") as file:
            content = await file.read()
            data = json.loads(content)
        return data

    async def write_json_file(self, data: dict | list[dict]):
        self.logger.info(f"Запись файла {self.file_path}")
        self.check_dir_exists()
        async with aiofiles.open(self.file_path, mode="w") as file:
            await file.write(json.dumps(data, ensure_ascii=False, indent=4))

    async def add_to_json_file(self, data: dict | list[dict]):
        self.logger.info(f"Добавление записей в файла {self.file_path}")
        if self.check_file_exists():
            async with aiofiles.open(self.file_path, mode="a") as file:
                await file.write(json.dumps(data, ensure_ascii=False, indent=4))


def get_file_path(file_id: int, file_name: str):
    return os.path.join(
        settings.incoming_path,
        settings.incoming_filename.format(id=file_id, file_name=file_name),
    )


async def remove_file(file_id: int, file_name: str) -> None:
    logger.info(f"Удаление файла {file_name}")
    file_path = get_file_path(file_id, file_name)
    if os.path.isfile(file_path):
        await aiofiles.os.remove(file_path)


async def write_file(file_id: int, content: UploadFile) -> None:
    logger.info(f"Запись файла {content.filename}")
    file_path = get_file_path(file_id, content.filename)

    if not os.path.isfile(file_path):
        async with aiofiles.open(file_path, mode="wb") as out_file:
            data = await content.read()
            await out_file.write(data)


async def get_pdf_number_of_pages(file_path: str) -> int:
    full_file_path = os.path.join(settings.incoming_path, file_path)

    if not os.path.isfile(full_file_path):
        return 0

    async with aiofiles.open(full_file_path, mode="rb") as file:
        pdf_data = await file.read()
        pdf_stream = io.BytesIO(pdf_data)
        pdf_reader = PyPDF2.PdfReader(pdf_stream)
        number_of_pages: int = len(pdf_reader.pages)

    return number_of_pages


async def write_ocr_file(file_path: str, content: dict | list[dict]) -> None:
    logger.info(f"Запись файла {file_path} с распознанными данными")
    async with aiofiles.open(file_path, mode="w") as file:
        await file.write(json.dumps(content, ensure_ascii=False, indent=4))


async def read_ocr_file(file_name: str) -> Any:
    logger.info(f"Чтение файла {file_name} с распознанными данными")
    full_file_path = os.path.join(settings.ocr_data_path, file_name)
    async with aiofiles.open(full_file_path, mode="r") as file:
        content = await file.read()
        data = json.loads(content)
    return data


async def get_ocr_files_list() -> list:
    logger.info("Получение списка файлов с распознанными данными")
    path = settings.ocr_data_path
    file_list = await aiofiles.os.listdir(path)
    pattern = r"\d+_.*"
    return [file for file in file_list if re.match(pattern, os.path.basename(file))]


async def add_to_file(file_path: str, content: dict | list[dict]) -> None:
    logger.info(f"Добавление записи в файл в файла {file_path}")
    async with aiofiles.open(file_path, mode="a") as file:
        await file.write(json.dumps(content, ensure_ascii=False, indent=4))


async def load_image_file(filename: str) -> bytes:
    try:
        async with aiofiles.open(filename, mode="rb") as file:
            return await file.read()
    except Exception as e:
        logger.error(f"Ошибка чтения файла {filename}: {e}")


async def load_image_files(paths: list[str]) -> list[bytes]:
    images = []
    for filename in paths:
        data = await load_image_file(filename)
        images.append(data)
    return images
